/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-11-15 09:22:55
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:00:54
 * @FilePath     : \openchaoji-corelib\shared\src\OpenChaoJi_os.c
 * @Description  :
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "OpenChaoJi_shared.h"

#if (OPENCHAOJI_CONFIG_MEMORY_MANAGER == OPENCHAOJI_CONFIG_MEMORY_TLSF)

#include "tlsf.h"

// 定义静态内存池大小
#define TLSF_POOL_SIZE (16*1024)
static uint8_t s_openchaoji_tlsf_memory_pool[TLSF_POOL_SIZE];
static tlsf_t s_tlsf = NULL;

// #define DEBUG_TLSF

#ifdef DEBUG_TLSF
typedef struct
{
    void * ptr;
    size_t size;
} Mem_t;

#define MAX_MEM 100
Mem_t s_mem[MAX_MEM];
int s_mem_count = 0;

void Debug_Mem()
{
    for (int i = 0; i < MAX_MEM; i++)
    {
        if (s_mem[i].ptr != NULL)
        {
            printf("mem[%d]: %p, size: %d\n", i, s_mem[i].ptr, s_mem[i].size);
        }
    }
    printf("mem_count: %d\n", s_mem_count);
}
#endif

bool OpenChaoJi_os_memeory_init()
{
    s_tlsf = tlsf_create_with_pool(s_openchaoji_tlsf_memory_pool, TLSF_POOL_SIZE);
    if (s_tlsf == NULL) {
        printf("TLSF initialization failed!\n");
        return false;
    }

    tlsf_walk_pool(tlsf_get_pool(s_tlsf), NULL, NULL);

    #ifdef DEBUG_TLSF
    memset(s_mem, 0, sizeof(s_mem));
    s_mem_count = 0;
    #endif

    return true;
}

void OpenChaoJi_os_memeory_term()
{
    if (s_tlsf != NULL) {
        tlsf_destroy(s_tlsf);
    }
}

void * OpenChaoJi_os_calloc(size_t _NumOfElements,size_t _SizeOfElements)
{
    void * ptr = OpenChaoJi_os_malloc(_NumOfElements * _SizeOfElements);
    if (ptr != NULL)
    {
        memset(ptr, 0, _NumOfElements * _SizeOfElements);
    }

    return ptr;
}

void OpenChaoJi_os_free(void *_Memory)
{
    // printf("free: %p\n", _Memory);
    if (s_tlsf == NULL) return;
    tlsf_free(s_tlsf, _Memory);

    #ifdef DEBUG_TLSF
    for (int i = 0; i < MAX_MEM; i++)
    {
        if (s_mem[i].ptr == _Memory)
        {
            s_mem[i].ptr = NULL;
            s_mem[i].size = 0;
            s_mem_count--;
            break;
        }
    }
    #endif
}

void * OpenChaoJi_os_malloc(size_t _Size)
{
    if (s_tlsf == NULL) return NULL;
    void * ptr = tlsf_malloc(s_tlsf, _Size);

    // tlsf_walk_pool(s_tlsf, NULL, NULL);
    if (ptr == NULL)
    {
        tlsf_walk_pool(tlsf_get_pool(s_tlsf), NULL, NULL);
        #ifdef DEBUG_TLSF
        Debug_Mem();
        #endif
        printf("TLSF malloc failed!\n");
    }
    // printf("malloc: %p\n", ptr);
    #ifdef DEBUG_TLSF
    if (ptr != NULL)
    {
        for (int i = 0; i < MAX_MEM; i++)
        {
            if (s_mem[i].ptr == NULL)
            {
                s_mem[i].ptr = ptr;
                s_mem[i].size = _Size;
                s_mem_count++;
                break;
            }
        }
    }
    #endif
    return ptr;
}

#endif

void OpenChaoJi_os_soft_timer_start(struct OpenChaoJi_os_soft_timer * timer, uint32_t timeout_ms)
{
    timer->timeout_ms = timeout_ms;
    timer->start_ticks = OpenChaoJi_os_get_ticks();
    timer->started = 1;
}

void OpenChaoJi_os_soft_timer_stop(struct OpenChaoJi_os_soft_timer * timer)
{
    timer->started = 0;
}
void OpenChaoJi_os_soft_timer_reset(struct OpenChaoJi_os_soft_timer * timer)
{
    timer->start_ticks = OpenChaoJi_os_get_ticks();
}

int  OpenChaoJi_os_soft_timer_is_stopped(struct OpenChaoJi_os_soft_timer * timer)
{
    return !timer->started;
}
int  OpenChaoJi_os_soft_timer_is_timeout(struct OpenChaoJi_os_soft_timer * timer)
{
    if (timer->started)
    {
        uint32_t diff = OpenChaoJi_os_get_ticks() - timer->start_ticks;
        return (diff >= timer->timeout_ms);
    }

    return 0;
}
